/*
 * \brief  Connection to a service
 * \author Norman Feske
 * \date   2008-08-22
 */

/*
 * Copyright (C) 2008-2009 Norman Feske
 * Genode Labs, Feske & Helmuth Systementwicklung GbR
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU General Public License version 2.
 */

#ifndef _INCLUDE__BASE__CONNECTION_H_
#define _INCLUDE__BASE__CONNECTION_H_

#include <base/env.h>

namespace Genode {

	/**
	 * Representation of an open connection to a service
	 *
	 * \param CT  Session-capability type
	 */
	template <typename CT>
	class Connection
	{
		public:

			enum On_destruction { CLOSE = false, KEEP_OPEN = true };

		private:

			CT _cap;
			On_destruction _on_destruction;

		public:

			/**
			 * Constructor
			 *
			 * \param cap  session capability
			 * \param od   session policy when destructing the connection
			 */
			Connection(CT cap, On_destruction od = CLOSE):
				_cap(cap), _on_destruction(od) { }

			/**
			 * Destructor
			 */
			~Connection()
			{
				if (_on_destruction == CLOSE)
					env()->parent()->close(_cap);
			}

			/**
			 * Return session capability
			 */
			CT cap() const { return _cap; }

			/**
			 * Define session policy
			 */
			void on_destruction(On_destruction od) { _on_destruction = od; }

			/**
			 * Shortcut for env()->parent()->session() function
			 */
			CT session(const char *service_name,
			           const char *format_args, ...)
			{
				/*
				 * The lock guards the serialized access of the format-string
				 * buffer. Because the argument string is used with the parent
				 * interface, the message-buffer size of the parent-interface
				 * provides a realistic upper bound for dimensioning the format-
				 * string buffer.
				 */
				static char buf[Parent::MSGBUF_SIZE];
				static Lock lock;
				Lock::Guard lock_guard(lock);

				/* process format string */
				va_list list;
				va_start(list, format_args);
				String_console sc(buf, sizeof(buf));
				sc.vprintf(format_args, list);

				/* call parent interface with the resulting argument buffer */
				return CT(env()->parent()->session(service_name, buf));
			}
	};
}

#endif /* _INCLUDE__BASE__CONNECTION_H_ */
